package com.eg366.nioLearn.baseSocket.chapter05;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;

import org.junit.Assert;

/**
 * (1)创建Selector
 * (2)创建ServerSocketChannel，并注册到Selector和监听accept，
 * (3)循环，获取已准备好的通道。判断是否准备好accept、读、写，并调用相应的操作方法
 */
public class TcpServerSelector {

	private static final int BUFSIZE = 256;
	private static final int TIMEOUT = 3000;

	public static void main(String[] args) throws IOException {
		args = new String[] { "1122" };
		Selector selector = Selector.open();

		for (String arg : args) {
			ServerSocketChannel serChannel = ServerSocketChannel.open();
			/* 非阻塞模式 */
			serChannel.configureBlocking(false);
			/* 监听指定端口号 */
			serChannel.socket().bind(new InetSocketAddress(Integer.parseInt(arg)));
			/* 为通道注册选择器 */
			serChannel.register(selector, SelectionKey.OP_ACCEPT);
		}
		/* 注册的SelectionKey数量 */
		Assert.assertTrue(selector.keys().size() == args.length);

		/* 创建协议操作器 */
		TcpProtocol protocol = new EchoSelectorProtocol(BUFSIZE);

		while (true) {
			/* 阻塞等待，直到有准备好I/O操作的通道。返回已准备好的通道的个数 */
			if (selector.select(TIMEOUT) == 0) {
				System.out.print("0");
				continue;
			}

			/* 返回集合中包含已准备好I/O操作通道的SelectionKey(在注册时创建)；进行迭代 */
			Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
			while (keyIter.hasNext()) {
				SelectionKey key = keyIter.next();
				/* 是否准备好接受新的socket连接 */
				if (key.isAcceptable()) {
					protocol.handleAccept(key);
				}
				/* 是否准备好读数据 */
				if (key.isReadable()) {
					protocol.handleRead(key);
				}
				/* 是否准备好写数据 */
				if (key.isValid() && key.isWritable()) {
					protocol.handleWrite(key);
				}
				/* 操作执行后，从集合中删除 */
				keyIter.remove();
			}
		}
	}
}
